//package com.wayhome.srpingbootmybatis.metrics.rpc;
//
//import feign.Client;
//import feign.Request;
//import feign.Response;
//import io.prometheus.client.Counter;
//import io.prometheus.client.Histogram;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.BeansException;
//import org.springframework.beans.factory.config.BeanPostProcessor;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
//import org.springframework.cloud.openfeign.FeignContext;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//import java.io.IOException;
//import java.net.URL;
//import java.util.HashMap;
//import java.util.Iterator;
//import java.util.Map;
//import java.util.concurrent.ConcurrentHashMap;
//
//@Configuration
//@ConditionalOnClass({Client.class, FeignContext.class})
//public class RpcMetrics {
//    private static Logger logger = LoggerFactory.getLogger(RpcMetrics.class);
//
//    @Bean
//    public FeignContextMetricsContextProcessor feignContextMetricsContextProcessor() {
//        return new FeignContextMetricsContextProcessor();
//    }
//
//    public static class FeignContextMetricsContextProcessor implements BeanPostProcessor {
//        @Override
//        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//            return bean instanceof FeignContext && !(bean instanceof FeignContextMetrics) ? new FeignContextMetrics((FeignContext)bean) : bean;
//        }
//    }
//
//    public static class FeignContextMetrics extends FeignContext {
//        private final FeignContext delegate;
//
//        FeignContextMetrics(FeignContext delegate) {
//            this.delegate = delegate;
//        }
//
//        public <T> T getInstance(String name, Class<T> type) {
//            T object = this.delegate.getInstance(name, type);
//            return this.wrap(object);
//        }
//
//        <T> T wrap(T bean) {
//            return bean instanceof Client && !(bean instanceof FeignClientMetricsWrapper) ? (T)new FeignClientMetricsWrapper((Client)bean) : bean;
//        }
//
//        public <T> Map<String, T> getInstances(String name, Class<T> type) {
//            Map<String, T> instances = this.delegate.getInstances(name, type);
//            if (instances == null) {
//                return null;
//            } else {
//                Map<String, T> convertedInstances = new HashMap();
//                Iterator iterator = instances.entrySet().iterator();
//
//                while (iterator.hasNext()) {
//                    Map.Entry<String, T> entry = (Map.Entry)iterator.next();
//                    convertedInstances.put(entry.getKey(), this.wrap(entry.getValue()));
//                }
//
//                return convertedInstances;
//            }
//        }
//    }
//
//    public static class FeignClientMetricsWrapper implements Client {
//        private Client client;
//        private static ConcurrentHashMap<String, Histogram> histogramMap = new ConcurrentHashMap<>();
//        private static final String ERROR_TAG = "rpc_unkown_service";
//        private static Counter errorCounter = Counter.build("rpc_io_error", "rpc call io error").labelNames("type").register(PrefixFilteredCollectorRegistry.getInstance());
//        public FeignClientMetricsWrapper(Client client) {
//            this.client = client;
//        }
//
//        @Override
//        public Response execute(Request request, Request.Options options) throws IOException {
//
//            Histogram.Timer timer = null;
//            String metricsName = ERROR_TAG;
//            try {
//                metricsName = getMetricsName(request.url());
//                if (histogramMap.get(metricsName) == null) {
//                    histogramMap.computeIfAbsent(metricsName, key -> create(key));
//                }
//                timer = histogramMap.get(metricsName).startTimer();
//            } catch (Throwable throwable) {
//            }
//            try {
//                return client.execute(request, options);
//            } catch (Throwable throwable) {
//                errorCounter.labels(metricsName).inc();
//                throw throwable;
//            } finally {
//                if (timer != null) {
//                    timer.observeDuration();
//                }
//            }
//        }
//
//        public static Histogram create(String key) {
//            return Histogram.build(key, key).register(PrefixFilteredCollectorRegistry.getInstance());
//        }
//
//        public String getMetricsName(String urlString) {
//            try {
//                StringBuilder stringBuilder = new StringBuilder("rpc");
//                URL url = new URL(urlString);
//                String path = url.getPath();
//                int index = path.indexOf("/api");
//                stringBuilder.append(path.substring(0, index).replaceAll("/", "_"));
//                return stringBuilder.toString();
//            } catch (Throwable e) {
//                return ERROR_TAG;
//            }
//        }
//    }
//}
